namespace Leetcode;
public static class Utils
{

    public static T[][] FromString2<T>(string s, System.Func<string, T> convert)
    {
        s = s?.Trim(new char[] { ' ' });
        if (string.IsNullOrWhiteSpace(s))
        {
            return new T[0][];
        }

        s = s.Substring(1, s.Length - 2).Trim();
        if (s == string.Empty)
        {
            return new T[0][];
        }


        var items = s.Split(new[] { "],[", "]\r,[", "]\n,[", "]\r\n,[", "],\r[", "],\n[", "],\r\n[" }, System.StringSplitOptions.None);
        var result = new T[items.Length][];
        for (int i = 0; i < result.Length; i++)
        {
            result[i] = FromString<T>(items[i].Trim(), convert);
        }
        return result;

    }

    public static T[] FromString<T>(string s, System.Func<string, T> convert)
    {
        if (string.IsNullOrWhiteSpace(s))
        {
            return new T[0];
        }
        var items = s.Trim(new char[] { '[', ']', ' ' }).Split(',', System.StringSplitOptions.RemoveEmptyEntries);
        var result = new T[items.Length];
        for (int i = 0; i < items.Length; i++)
        {
            var item = items[i].Trim();
            if (item.StartsWith("\"") && item.EndsWith("\""))
            {
                if (item.Length == 2)
                {
                    item = string.Empty;
                }
                else if (item.Length > 2)
                {
                    item = item.Substring(1, item.Length - 2);
                }
            }
            result[i] = convert(item);
        }
        return result;
    }


    public static TreeNode TreeNodeFromString(string s)
    {
        var serializer = new TreeCodeSerializer();
        return serializer.Deserialize<TreeNode, int>(s, i => int.Parse(i));
    }

    public static TNode TreeNodeFromString<TNode, TValue>(string s, Func<string, TValue> func)
     where TNode : class, ITreeNode<TValue>, new()
        where TValue : struct
    {
        var serializer = new TreeCodeSerializer();
        return serializer.Deserialize<TNode, TValue>(s, func);
    }

    public static ListNode ListNodeFromString(string s)
    {
        var serializer = new ListNodeSerializer();
        return serializer.Deserialize(s);
    }

    public static string ToString(ListNode head)
    {
        var serializer = new ListNodeSerializer();
        return serializer.Serialize(head);
    }
    public static char[] CharFromString(string s)
    {
        return FromString<char>(s, (v) => v[0]);
    }

    public static char[][] CharFromString2(string s)
    {
        return FromString2<char>(s, (v) => v[0]);
    }

    public static int[] IntFromString(string s)
    {
        return FromString<int>(s, (v) => int.Parse(v));
    }

    public static int[][] IntFromString2(string s)
    {
        return FromString2<int>(s, (v) => int.Parse(v));
    }

    public static string[] StringFromString(string s)
    {
        return FromString<string>(s, (v) => v);
    }

    public static string[][] StringFromString2(string s)
    {
        return FromString2<string>(s, (v) => v);
    }

    public static string ToString<T>(IEnumerable<T> values, System.Func<T, string> convert)
    {
        return $"[{string.Join(',', values.Select(convert))}]";
    }

    public static string ToString<T>(IEnumerable<IEnumerable<T>> values, System.Func<T, string> convert)
    {
        var rows = values.Select(_ => ToString(_, convert));

        return ToString(values.Select(_ => ToString(_, convert)));
    }

    public static string ToString(IEnumerable<string> values)
    {
        return ToString<string>(values, _ => _);
    }

    public static string ToString(IEnumerable<string[]> values)
    {
        return ToString<string>(values, _ => _);
    }

    public static string ToString(IEnumerable<IList<string>> values)
    {
        return ToString<string>(values, _ => _);
    }

    public static string ToString(IEnumerable<int[]> values)
    {
        return ToString<int>(values, _ => _.ToString());
    }

    public static string ToString(IEnumerable<IList<int>> values)
    {
        return ToString<int>(values, _ => _.ToString());
    }

    public static string ToString(IEnumerable<char[]> values)
    {
        return ToString<char>(values, _ => _.ToString());
    }

    public static string ToString(IEnumerable<int> values)
    {
        return ToString<int>(values, _ => _.ToString());
    }

    public static string ToString<T>(ITreeNode<T> treeNode)
    {
        return (new TreeCodeSerializer()).Serialize(treeNode);
    }

    public static int[] GenNum(int count, int from, int to)
    {
        var r = new System.Random();
        var result = new int[count];
        for (var i = 0; i < count; i++)
        {
            result[i] = r.Next(from, to);
        }
        return result;
    }

    public static int[][] GenNum(int count1, int count2, int from, int to, Func<int, int, int> genVal = null)
    {
        var r = new System.Random();
        var result = new int[count1][];

        for (int i = 0; i < result.Length; i++)
        {
            result[i] = new int[count2];
            for (int j = 0; j < count2; j++)
            {
                result[i][j] = genVal == null ? r.Next(from, to) : genVal(i, j);
            }
        }
        return result;
    }

    public static string GenNumString(int count, int from, int to)
    {
        var vals = GenNum(count, from, to);
        var r = ToString(vals);
        return r;
    }

    public static string GenNumString(int count1, int count2, int from, int to)
    {
        var vals = GenNum(count1, count2, from, to);
        var r = ToString(vals);
        return r;
    }

    public static string GenLowCaseLetters(int count, char from = 'a', char to = 'z')
    {
        var r = new System.Random();
        var result = new char[count];
        var min = from - 'a';
        var max = to - 'a' + 1;
        for (var i = 0; i < count; i++)
        {
            result[i] = (char)('a' + r.Next(min, max));
        }
        return new string(result);
    }

    public static void Print(IEnumerable<IEnumerable<int>> value)
    {
        foreach (var item in value)
        {
            Print(item);
        }
    }

    public static void Print2<T>(IEnumerable<IEnumerable<T>> value)
    {
        Print<T>(value, i => i.ToString());
    }

    public static void Print<T>(IEnumerable<IEnumerable<T>> value, Func<T, string> toString)
    {
        foreach (var item in value)
        {
            Print(item, toString);
        }
    }

    public static void Print(IEnumerable<int> value)
    {
        Console.WriteLine(ToString(value));
    }

    public static void Print<T>(IEnumerable<T> value)
    {
        Print(value, _ => _.ToString());
    }

    public static void Print<T>(IEnumerable<T> value, Func<T, string> toString)
    {
        Console.WriteLine(ToString<T>(value, toString));
    }
}
